package gcommand

import (
	"Ghost/ntk"
	. "Ghost/utd"
	"Ghosted/pack"
	"errors"
	"fmt"
	"github.com/lxn/walk"
	"time"
)

var TheCtrl *MainControl = &MainControl{}

type MainControl struct {
	settings    *walk.IniFileSettings
	connect     ntk.ITcpConnecter
	logined     bool
	msgHandlers map[uint16]ntk.MessageCHandler

	pingMsg      ntk.IMsger
	lastPingTime time.Time

	mapCenterNodes map[int]*pack.PtNetNode
}

func (this *MainControl) Init() {

	this.msgHandlers = make(map[uint16]ntk.MessageCHandler)
	this.lastPingTime, this.pingMsg = time.Now(), pack.MakeMsgPingServer()

	this.mapCenterNodes = make(map[int]*pack.PtNetNode)

	TheConfig.Init(DEF_CONFIG_PATH)

	TheModelLogin.Init()

	TheView.Create(TheModel)
	TheView.SetX(TheConfig.Config.PosX)
	TheView.SetY(TheConfig.Config.PosY)

	this.SyncFunc(func() { this.Start() })
	this.StartTimer()

	this.RegistMsgHandler(pack.MT_PING_SERVER, this.OnMsgPingServer)
	this.RegistMsgHandler(pack.MT_LOGIN_ACCOUNT_ACK, this.OnMsgLoginA)
	this.RegistMsgHandler(pack.MT_EXEC_ADMIN_CMD, this.OnMsgExecAdminCmd)
	this.RegistMsgHandler(pack.MT_SYN_CENTER_NODE, this.OnMsgPushServerList)
}
func (this *MainControl) Start() {
	UHelp.IFCast(TheConfig.Valid(), func() { this.ConnectRoost(false) }, func() { this.RunViewLogin(nil) })
}
func (this *MainControl) Run() {
	this.Init()

	TheView.Run()

	UHelp.IFCast(this.logined, func() { TheConfig.Save() }, nil)
}
func (this *MainControl) Exit() {
	TheView.Close()
}
func (this *MainControl) SyncFunc(fun func()) {
	TheView.Synchronize(fun)
}
func (this *MainControl) StartTimer() {
	go func() {
		ticker := time.NewTicker(time.Second)
		for {
			select {
			case <-ticker.C:
				this.SyncFunc(func() { this.OnMainTimer() })
			}
		}
	}()
}
func (this *MainControl) ConnectRoost(asyn bool) {
	TheModelLogin.SetErrorTip("", false)
	TheModelLogin.SetLoginText("正在登陆...", true)
	connect := ntk.NewTcpConnect(this)
	connFun := func() {
		err := connect.StartConnect(TheModelLogin.RoostHost, DEF_CONNECT_TIMEOUT, ntk.DEF_SEND_CHAN_SIZE)
		if err != nil {
			this.SyncFunc(func() { this.OnHandConnError(err) })
			return
		}
		this.connect = connect
	}
	UHelp.IFCast(asyn, func() { go connFun() }, func() { connFun() })
}
func (this *MainControl) SaveWinPos(nX, nY int) {
	TheConfig.Config.PosX = nX
	TheConfig.Config.PosY = nY
}
func (this *MainControl) RunViewLogin(owner walk.Form) {
	TheModelLogin.SetLoginText("登 陆", false)

	UHelp.IFCast(TheViewLogin.Created(),
		func() { TheViewLogin.Show() },
		func() { TheViewLogin.Create(owner, TheModelLogin) })

	TheViewLogin.SetX(TheView.X() + TheViewLogin.Width()/2)
	TheViewLogin.SetY(TheView.Y() + TheViewLogin.Height()/2)
	UHelp.IFCast(TheViewLogin.Run() == 0, func() { this.Exit() }, nil)
}
func (this *MainControl) UpdateNodeList(centerIndex int) {
	serId := TheModel.centers.items[centerIndex].ServerId

	centerNode := this.mapCenterNodes[int(serId)]
	nodeList := make([]*pack.PtNetNode, 0, len(centerNode.Nodes)+1)
	nodeList = append(nodeList, centerNode)
	nodeList = append(nodeList, centerNode.Nodes...)

	TheModel.nodes.UpdateData(nodeList)
}

//------------------------------------------------------------------------------
//=========================MainControl - 自己回调方法===========================
//------------------------------------------------------------------------------
func (this *MainControl) OnMainTimer() {
	this.TickPingMessage()
}
func (this *MainControl) OnHandConnect() {
	msg := pack.MakeMsgLoginQ()
	msg.Account = TheModelLogin.Account
	bPwd, _ := UCode.HashValueXX(UECHT_MD5, []byte(TheModelLogin.Password))
	msg.Password = string(bPwd)
	this.connect.SendMessage(msg)

	UMain.Infof("Connect RoostServer[%s] OK.", TheModelLogin.RoostHost)
}
func (this *MainControl) OnHandConnError(err error) {
	UHelp.IFCast(this.connect != nil, func() { this.connect.CloseConnect(err) }, nil)
	TheModelLogin.SetErrorTip(err.Error(), true)
	if TheView.Visible() {
		this.RunViewLogin(TheView)
	} else {
		this.RunViewLogin(nil)
	}
}
func (this *MainControl) OnHandMessage(msg ntk.IMsger) {
	if handle, ok := this.msgHandlers[msg.GetHead().GetType()]; ok {
		handle(msg)
		return
	}
	if handle, ok := this.msgHandlers[ntk.DEF_DEFAULT_MSGTYPE]; ok {
		handle(msg)
		return
	}
	UMain.Warnf("unknow msg[%s] ", ntk.MessageName(msg))
}
func (this *MainControl) RegistMsgHandler(msgType uint16, handle ntk.MessageCHandler) {
	if _, ok := this.msgHandlers[msgType]; ok {
		UMain.Warnf("msgType[%s] is repeated registed.", ntk.MessageNameT(msgType))
	}
	this.msgHandlers[msgType] = handle
}

//------------------------------------------------------------------------------
//=========================MainControl - 定时更新方法===========================
//------------------------------------------------------------------------------
func (this *MainControl) TickPingMessage() {
	if time.Since(this.lastPingTime) <= DEF_PINGMSG_GAP_TIME {
		return
	}
	this.lastPingTime = time.Now()
	msg := this.pingMsg.(*pack.MsgPingServer)
	msg.Time = this.lastPingTime.UnixNano()
	UHelp.IFCast(this.connect != nil, func() { this.connect.SendMessage(this.pingMsg) }, nil)
}

//------------------------------------------------------------------------------
//=========================MainControl - 消息处理方法===========================
//------------------------------------------------------------------------------
func (this *MainControl) OnMsgPingServer(msg ntk.IMsger) {
	ack := msg.(*pack.MsgPingServer)
	gap := time.Since(time.Unix(0, ack.Time))
	info := fmt.Sprintf("%fms [%v]", float64(gap)/1e6, gap)
	TheModel.SetServerInfo(info, true)
}
func (this *MainControl) OnMsgLoginA(msg ntk.IMsger) {
	ack := msg.(*pack.MsgLoginA)
	if ack.Result != pack.PELoginResult_Success {
		this.OnHandConnError(errors.New(ack.Result.String()))
		return
	}

	this.logined = true
	TheModelLogin.SetErrorTip("", false)
	TheModelLogin.SetLoginText("登 陆", false)
	UHelp.IFCast(TheViewLogin.Created() && TheViewLogin.Visible(),
		func() { TheModelLogin.dbind.Submit(); TheViewLogin.Accept() }, nil)

	TheView.Show()
}
func (this *MainControl) OnMsgExecAdminCmd(msg ntk.IMsger) {
	ack := msg.(*pack.MsgExecAdminCmd)
	TheView.ShowAdminCommand(ack.CenterId, ack.ServerInfo.ServerId, ack.CmdAck)
}
func (this *MainControl) OnMsgPushServerList(msg ntk.IMsger) {
	list := msg.(*pack.MsgPushServerList)
	if len(list.CenterList) == 0 {
		return
	}
	for _, item := range list.CenterList {
		this.mapCenterNodes[int(item.ServerId)] = item
	}
	TheModel.centers.UpdateData(list.CenterList)
	nodeList := make([]*pack.PtNetNode, 0, len(list.CenterList[0].Nodes)+1)
	nodeList = append(nodeList, list.CenterList[0])
	nodeList = append(nodeList, list.CenterList[0].Nodes...)
	UMain.Print("format:", len(nodeList))
	TheModel.nodes.UpdateData(nodeList)
	TheView.InitNodeList()
}
func (this *MainControl) SendAdminCommand(centerId int32, node *pack.PtNetNode, str string) {
	TheModel.input.Insert(str)

	msg := pack.MakeMsgExecAdminCmd()
	msg.CenterId = centerId
	msg.ServerInfo = &pack.PtServerInfo{node.ServerType, node.ServerId}
	// msg.OperateId
	// msg.ExecTime
	msg.CmdReq = str
	this.connect.SendMessage(msg)
}

//------------------------------------------------------------------------------
//=========================MainControl - 连接回调方法===========================
//------------------------------------------------------------------------------

func (this *MainControl) OnNetConnected() {
	this.SyncFunc(func() { this.OnHandConnect() })
}
func (this *MainControl) OnNetConnError(err error) {
	this.SyncFunc(func() { this.OnHandConnError(err) })
}
func (this *MainControl) OnNetMessage(msg ntk.IMsger) {
	this.SyncFunc(func() { this.OnHandMessage(msg) })
}
